from xenocide import *
from interface import Button
import sys

class fwBoundaryListener(box2d.b2BoundaryListener):
    """
    The boundary listener callback:
    Violation is called when the specified body leaves the world AABB.
    """
    test = None
    def __init__(self):
        super(fwBoundaryListener, self).__init__()

    def Violation(self, body):
        # So long as it's not the user-created bomb, let the test know that
        # the specific body has left the world AABB
        pass

class GameState(object):
    name="VOID"
    
    def __init__(self,iName,iTitle,iWindow):
        self.name=iName
        self.title=iTitle
        self.window=iWindow
        
        self.keys=iWindow.keys
        
        
    def activate(self):
        self.window.push_handlers(self)
        
    def deActivate(self):
        self.window.remove_handlers(self)
        
    def step(self,dt):
        pass
    
    def draw(self,dt):
        pass
        
    def on_mouse_press(self, x, y, button, modifiers):
        return False
    
    def on_mouse_release(self, x, y, button, modifiers):
        return False
    
    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        return False
    
    def on_key_press(self, symbol, modifiers):
        return False

class Banner(GameState):
    def __init__(self, iName,iTitle,iWindow, dismiss_func=None, timeout=None):
        
        super(Banner,self).__init__(iName,iTitle,iWindow)
        self.text = pyglet.text.Label(iTitle,
                                      font_name=iWindow.fontName,
                                      font_size=36,
                                      x=iWindow.width // 2, 
                                      y=iWindow.height // 2,
                                      anchor_x='center',
                                      anchor_y='center')

        self.dismiss_func = dismiss_func
        self.timeout = timeout
        if timeout and dismiss_func:
            pyglet.clock.schedule_once(dismiss_func, timeout)

    def draw(self,dt):
        self.text.draw()

    def on_key_press(self, symbol, modifiers):
        if self.dismiss_func and not self.timeout:
            self.dismiss_func()
        return True

class Menu(GameState):
       
    def __init__(self,iName,iTitle,iWindow,iFontName):
        super(Menu,self).__init__(iName,iTitle,iWindow)
        self.fontName=iFontName
        self.items = []
        self.title_text = pyglet.text.Label(iTitle, 
                                            font_name=self.fontName,
                                            font_size=36,
                                            x=self.window.width // 2, 
                                            y=460,
                                            anchor_x='center',
                                            anchor_y='center',
                                            color=[255,255,255,255])

    def reset(self):
        self.selected_index = 0
        self.items[self.selected_index].selected = True

    def on_key_press(self, symbol, modifiers):
        if symbol == pyglet.window.key.DOWN:
            self.selected_index += 1
        elif symbol == pyglet.window.key.UP:
            self.selected_index -= 1
        else:
            self.items[self.selected_index].on_key_press(symbol, modifiers)
        self.selected_index = min(max(self.selected_index, 0), 
                                  len(self.items) - 1)

##        if symbol in (pyglet.window.key.DOWN, pyglet.window.key.UP) and self.window.enable_sound:
##            bullet_sound.play()

    def draw(self,dt):
        gl.glPushAttrib(gl.GL_CURRENT_BIT)
        gl.glColor3f(1.0,1.0,1.0)
        self.title_text.draw()
        for i, item in enumerate(self.items):
            item.draw(i == self.selected_index)
        gl.glPopAttrib()
        
    
class MainMenu(Menu):
    def __init__(self,iName,iTitle,iWindow,iFontName):
        super(MainMenu, self).__init__(iName,iTitle,iWindow,iFontName)
        
        self.cursorImage=pyglet.resource.image('pointer.png')
        self.cursorImage.anchor_x = self.cursorImage.width // 2
        self.cursorImage.anchor_y = self.cursorImage.height // 2
        self.cursorImage_flip = pyglet.resource.image('pointer.png', flip_x=True)
        

        self.items.append(MenuItem(self,'New Game',340, self.begin_game))
        self.items.append(MenuItem(self,'Instructions', 300, 
                                   self.begin_instructions_menu))
        self.items.append(MenuItem(self,'Options', 260, self.begin_options_menu))
        self.items.append(MenuItem(self,'Quit', 220, sys.exit))
        
        self.reset()

    def begin_game(self):
        G=gsGame("Game","XENOCIDE",self.window)
        
        self.window.switchGameState(G)
        

    def begin_instructions_menu(self):
        G=gsInstructions("instructions","INSTRUCTIONS",self.window)
        
        self.window.switchGS(G)
    
    def begin_options_menu(self):
        G=gsInstructions("options","OPTIONS",self.window)
        
        self.window.switchGS(G)
        

class MenuItem(object):
    pointer_color = (.46, 0, 1.)
    inverted_pointers = False

    def __init__(self, iWindow,label, y, activate_func):
        self.y = y
        self.window=iWindow
        self.pointer_image=iWindow.cursorImage
        self.pointer_image_flip=iWindow.cursorImage_flip
        self.text = pyglet.text.Label(label,
                                      font_name=self.window.fontName,
                                      font_size=14,
                                      x=iWindow.window.width // 2, 
                                      y=y,
                                      anchor_x='center',
                                      anchor_y='center',
                                      color=[255,180,0,255])
        self.activate_func = activate_func
        print iWindow.window.width // 2
    def draw_pointer(self, x, y, color, flip=False):
       
        # Tint the pointer image to a color
        gl.glPushAttrib(gl.GL_CURRENT_BIT)
        gl.glColor3f(*color)
        if flip:
            self.pointer_image_flip.blit(x, y)
        else:
            self.pointer_image.blit(x, y)
        gl.glPopAttrib()

    def draw(self, selected):
        
        
        self.text.draw()

        if selected:
            
            self.draw_pointer(
                self.text.x - self.text.content_width / 2 - 
                    self.pointer_image.width / 2,
                self.y, 
                self.pointer_color,
                self.inverted_pointers)
            self.draw_pointer(
                self.text.x + self.text.content_width / 2 + 
                    self.pointer_image.width / 2,
                self.y,
                self.pointer_color,
                not self.inverted_pointers)

    def on_key_press(self, symbol, modifiers):
        if symbol == pyglet.window.key.ENTER and self.activate_func:
            self.activate_func()
            if self.window.parent.enable_sound:
                bullet_sound.play()

class ToggleMenuItem(MenuItem):
    pointer_color = (.27, .82, .25)
    inverted_pointers = True

    def __init__(self, iWindow,label, value, y, toggle_func):
        
        self.value = value
        self.label = label
        self.toggle_func = toggle_func
        super(ToggleMenuItem, self).__init__(iWindow,self.get_label(), y, None)

    def get_label(self):
        return self.label + (self.value and ': ON' or ': OFF')

    def on_key_press(self, symbol, modifiers):
        if symbol == key.LEFT or symbol == key.RIGHT:
            self.value = not self.value
            self.text.text = self.get_label()
            self.toggle_func(self.value)
            if self.window.options["enable_sound"]:
                bullet_sound.play()

class xenSettings(object):
    hz=60.0
    velocityIterations=10
    positionIterations=8
    drawStats=False
    drawShapes=True
    drawControllers=True
    drawJoints=True
    drawCoreShapes=False
    drawAABBs=False
    drawOBBs=False
    drawPairs=False
    drawContactPoints=False
    drawContactNormals=False
    drawContactForces=False
    drawFrictionForces=False
    drawCOMs=False
    enableWarmStarting=True
    enableTOI=True
    pause=False
    singleStep=False
    drawFPS=True # python version
    pointSize=2.5 # python version (pixel radius for drawing points)
    drawMenu=True #toggle by pressing F1
class xenDestructionListener(box2d.b2DestructionListener):
    """
    The destruction listener callback:
    "SayGoodbye" is called when a joint is deleted.
    """
    test = None
    def __init__(self):
        super(xenDestructionListener, self).__init__()

    def SayGoodbye(self, joint):
        pass

class gsGame(GameState):
    def __init__(self,iName,iTitle,iWindow):
        super(gsGame,self).__init__(iName,iTitle,iWindow)
        
        self.settings=xenSettings()

        
        self.worldAABB = box2d.b2AABB()
        self.points = []
        self.world = None
        #self.settings = fwSettings()
        self.mouseWorld = None

        # Box2D-callbacks
        self.destructionListener = None
        self.boundaryListener = None
        self.contactListener = None
        self.debugDraw = None
        self.dd_on=True
        
        self.initSprites()

        
        k_restitution = 0.4    
        self.worldDimensions=(0,0)
        
        self.icebergs=[]
        self.ore=[]
        self.selected=None
        self.selectedActors=[]
        self.actors=[]
        self.actorCount=0
        self.beaconCount=0
        
        self.loadLevel("level1")        
        
        
        
        self.destructionListener = xenDestructionListener()
        self.boundaryListener = fwBoundaryListener()
        self.contactListener = xenContactListener()
        self.debugDraw = fwDebugDraw()

        self.debugDraw.surface = self.window.screen

        self.destructionListener.test = self
        self.boundaryListener.test = self
        self.contactListener.test = self
        
        self.world.SetDestructionListener(self.destructionListener)
        self.world.SetBoundaryListener(self.boundaryListener)
        self.world.SetContactListener(self.contactListener)
        self.world.SetDebugDraw(self.debugDraw)
           
        
        
        
        
##        self.beaconCount=0
##        self.beacons={}
        
        
        
        self.windows=[]
        ww,wh=self.window.screenSize
        
        
        self.mainWindow=SubWindow3D(self,[401,00],[ww-401,wh],
                            [80,80],1.)
        self.cpWindow=SubWindowCP(self,[0,0],[400,wh],
                            [80,80],1.,self.getTexture("ControlPanel"))
        self.windows.append(self.mainWindow)
        self.window.push_handlers(self.mainWindow)
        
        self.windows.append(self.cpWindow)
        self.window.push_handlers(self.cpWindow)
        
        
    def compileDictionary(self,bList):
        
        D={}
        for b in bList:
            D[b]=b.neighbours
        return D
        
        
        
    def computePath(self,iFrom,iTo):
        #takes two b2Vec2 as start and end
        B=[]
        for b in self.actors:
            if b.desc=="Beacon":
                B.append(b)

        #find closest beacon
        dist=10000000
        start=None
        for b in B:
            p=b.getPosition(False)
            C=(iFrom-p)
            d=C.LengthSquared()
            if d<dist :
                dist=d
                start=b
            
        if not start:
            print "No Beacon Found !"
            return None
        #print "start Beacon %s at %s"%(start.name,str(start.getPosition(True)))
        #find closest beacon
        dist=10000000
        end=None
        for b in B:
            p=b.getPosition(False)
            C=(iTo-p)
            d=C.LengthSquared()
            if d<dist :
                dist=d
                end=b
            
        if not end:
            print "No Beacon Found !"
            return None
        #print "end Beacon %s at %s"%(end.name,str(end.getPosition(True)))
        
        D=self.compileDictionary(B)
        
        b2=dijkstra.shortestPath(D,start,end)
        path=[]
        #print b2
        for b in b2:
            path.append(b.getPosition(False))
        path.append(iTo)
        #print path
        return path
    
    
    def getVisibleNeighbours(self,actor,range):
        
        visible=[]
        
        for a in self.actors:
            if a.body:
                vc=actor.visibilityCheck(a,range)
                if vc :
                    visible.append(vc)
        return visible
    

    
    def activate(self):
        self.window.push_handlers(self)
        for w in self.windows:
            self.window.push_handlers(w)
        
    def deActivate(self):
        self.window.remove_handlers(self)
        for w in self.windows:
            self.window.remove_handlers(w)
   
    def initSprites(self):
        
        names=['Icon1','Icon1_des','HealthBar1','Voyant1','Voyant2','Voyant3']
        self.images={}
        
        #convertir icons en  dictionnaire 'images'
        self.icons = [pyglet.resource.image(nm+'.png') for nm in names]
        for ic in self.icons:
            ic.anchor_x=ic.width//2
            ic.anchor_y=ic.height//2
            
        img_names=["red_light",'orange_light','violet_light','pink_light','ControlPanel','homebase_selected','homebase','launchpad','launchpad_selected']
        
        for N in img_names:
            
            self.images[N]=pyglet.resource.image(N+'.png')
            self.center_anchor(self.images[N])
##            self.spriteAnims[N]=self.makeZoomAnim( \
##                self.images[N],0.5,1.5, 10,1.,True)
##        
    def center_anchor(self,img):
        img.anchor_x = img.width // 2
        img.anchor_y = img.height // 2
    def makeZoomAnim(self,img,min,max,nSteps,iPeriod,iLoop):
        w=img.width
        h=img.height
        
        tex=img.get_texture()
        
        
        dest=pyglet.image.Texture(0,0,w*nSteps,h)
        tex_dest=dest
        for i in range(nSteps):
            fact=(float(max)-float(min))/nSteps+float(min)
            gl.glLoadIdentity()
            gl.glTranslatef(w*(i+0.5),h/2,0)
            gl.glScalef(fact,fact,1.0)
            tex.blit_into(dest,0,0,0)
        gl.glLoadIdentity()
        
        dest_images = pyglet.image.ImageGrid(dest_image, 1, nSteps)
        dest_images = map(self.center_anchor,dest_images.get_texture_sequence())
        
        dest_animation = \
            pyglet.image.Animation.from_image_sequence(dest_images,
                                               iPeriod,
                                               loop=iLoop)
        if True:
            dest_image.save("anim.png")
        
    def getTexture(self,name):
        if self.images.has_key(name):
            return self.images[name].get_texture()
        else :
            return None
        
    def loadLevel(self, iFileName):
        
        pData=pyglet.resource.text( iFileName+".svg")
        xmlstr=pData.text
        svg=SVGParser(xmlstr)
        
        minX=minY=0.0
        maxX,maxY=svg.getDimensions()
        
        base_pos=svg.getBasePosition()
        self.viewCenter=box2d.b2Vec2(*base_pos)
        
        # Box2D Initialization
        self.worldAABB.lowerBound.Set(minX,minY)
        self.worldAABB.upperBound.Set( maxX, maxY)
        
        gravity = box2d.b2Vec2(0.0, 0.0)
        doSleep = True  
        self.world = box2d.b2World(self.worldAABB, gravity, doSleep)
        
        bd=box2d.b2BodyDef() 
        bd.position.Set(0.0,0.0)
        self.ground = self.world.CreateBody(bd) 
       
        #LOAD the floating icebergs from a svg file
        
        self.worldDimensions=svg.dimensions
        
        factor=svg.getScale()
        
        pData=pyglet.resource.text( "silhouette_actor.svg")
        xmlstr=pData.text
        svg2=SVGParser(xmlstr,factor)
        
        self.actorContour=svg2.getPaths()[0][0:-1]
        
        pData=pyglet.resource.text( "silhouetteBase.svg")
        xmlstr=pData.text
        svg2=SVGParser(xmlstr,factor)
        
        self.baseContour=svg2.getPaths()[0][0:-1]
        
        
        self.homeBase=self.spawnHomeBase(box2d.b2Vec2(*base_pos))

        
        for i,pt in enumerate(svg.getPaths()):
            name="Iceberg#%d"%(i)
            
            self.icebergs.append(Iceberg(self.world,name,pt[0:-1]))
        
        
        
    
    def on_show(self):
        """
        Callback: the window was shown.
        """
        for w in self.windows:
            w.calculateExtents()
            w.prepareView()
        
    def step(self, dt):
        
        
        # Step the physics
        
        
        
        self.contactListener.reset()
        
        """
        The main physics step.

        Takes care of physics drawing (callbacks are executed after the world.Step() )
        and drawing additional information.
        """

        # Don't do anything if the setting's Hz are <= 0
        timeStep = 1.0 / self.settings.hz
        
        
        
        # Set the flags based on what the settings show (uses a bitwise or mask)
        
        self.debugDraw.batch = pyglet.graphics.Batch()
        flags = 0
        if True:     flags |= box2d.b2DebugDraw.e_shapeBit
##        if True:     flags |= box2d.b2DebugDraw.e_jointBit
##        if True:flags |= box2d.b2DebugDraw.e_controllerBit
##        if True: flags |= box2d.b2DebugDraw.e_coreShapeBit
##        if True:      flags |= box2d.b2DebugDraw.e_aabbBit
##        if True:       flags |= box2d.b2DebugDraw.e_obbBit
##        if True:      flags |= box2d.b2DebugDraw.e_pairBit
##        if True:       flags |= box2d.b2DebugDraw.e_centerOfMassBit
        self.debugDraw.SetFlags(flags)


        # Set the other settings that aren't contained in the flags
        self.world.SetWarmStarting(self.settings.enableWarmStarting)
        self.world.SetContinuousPhysics(self.settings.enableTOI)

        
        # Tell Box2D to step
        self.world.Step(timeStep, self.settings.velocityIterations, self.settings.positionIterations)
        self.world.Validate()

    
        self.checkCollisions()
        for a in self.actors:
            #a.update()
            a.step(dt)
        
        dead=[a for a in self.actors if a.isDead]
        
        for a in dead:
            print "%s is Dead !"%(a.name)
            self.actors.remove(a)            
            a.dispose()
            
            
                
        
    
    def draw(self,dt):
        # Create a new batch for drawing
            

        # Draw the title of the test at the top
        #self.DrawString(5, 15, self.name)
        #self.mainWindow.calculateExtents()
        self.mainWindow.prepareView()

        for a in self.actors:
            a.drawComponents(dt)
        
        for a in self.actors:
            a.draw(dt)
                
        if self.dd_on:
            
            self.debugDraw.batch.draw()
        
        self.mainWindow.draw()
        self.cpWindow.prepareView()

        
        
        self.cpWindow.draw()
    
    def checkCollisions(self):
        # Traverse the contact results. Destroy bodies that
        # are touching heavier bodies.
        
        
        l=self.contactListener.getCollisionEffects()
        if len(l)>0:
            for a in l.keys():
                a.applyDamage(l[a])
                         
  
    
    def spawnBomb(self,pos=None):
        name="Actor #%i"%(self.actorCount)
        self.actorCount+=1
        if not pos:
            pos=self.mainWindow.mouseWorld
        if not pos:
            return None
        act=BombActor(self,name,pos,None,self.icons)
        self.actors.append(act)
        return act

    
    def spawnHomeBase(self,pos=None):
        name="HomeBase #%i"%(self.actorCount)
        self.actorCount+=1
        if not pos:
            pos=self.mainWindow.mouseWorld
        if not pos:
            return None
        act=HomeBase(self,name,pos,self.baseContour,(self.getTexture('homebase_selected'),self.getTexture('homebase')))
        self.actors.append(act)
        return act

    
    def spawnActor(self,pos=None):
        name="Actor #%i"%(self.actorCount)
        self.actorCount+=1
        exHB=False
        if not pos:
            exHB=True
            pos=self.homeBase.getPosition(False)+box2d.b2Vec2(0.,8.)
        if not pos:
            return None
        act=MovingActor(self,name,pos,None,self.icons)
        self.actors.append(act)
        if exHB==True:
            data={}
            data['Position']=pos+box2d.b2Vec2(0.,10.)
            data['Modifiers']=0
            data['Target']=None
            act.doAction(data)  
            self.selectActor(act,True)
            
        return act

    def spawnBeacon(self,pos=None):
        name="Beacon #%i"%(self.beaconCount)
        self.beaconCount+=1
        if not pos:
            pos=self.mainWindow.mouseWorld
        if not pos:
            return None
        act=Beacon(self,name,pos)
        self.actors.append(act)
        return act
        
    def spawnTractor(self,pos=None):
        name="Actor #%i"%(self.actorCount)
        self.actorCount+=1
        exHB=False
        if not pos:
            exHB=True
            pos=self.homeBase.getPosition(False)+box2d.b2Vec2(0.,8.)
        if not pos:
            return None
        act=Transporter(self,name,pos,None,self.icons)
        self.actors.append(act)
        if exHB==True:
            data={}
            data['Position']=pos+box2d.b2Vec2(0.,10.)
            data['Modifiers']=0
            data['Target']=None
            act.doAction(data)  
            self.selectActor(act,True)
            
        return act
    
   
    def on_key_press(self, key, modifiers):
        """
        Checks for the initial keydown of the basic testbed keys. Passes the unused
        ones onto the test via the Keyboard() function.
        """
        
        if key==pyglet.window.key.BACKSPACE:
            self.dd_on=not self.dd_on
            return

        if key==pyglet.window.key._3:
            
            act=self.spawnBeacon()
            if act:
                self.selectActor(act,True)
            return

        if key==pyglet.window.key._4:
            
            act=self.spawnBomb()
            if act:
                self.selectActor(act,True)
            return

        if key==pyglet.window.key._2:
            
            act=self.spawnTractor()
            if act:
                self.selectActor(act,True)
            return

        if key==pyglet.window.key._1:
            
            act=self.spawnActor()
            if act:
                self.selectActor(act,True)
            return
        
        if len(self.selectedActors)>0:
            for a in self.selectedActors:
                a.doKeyEvent(key)


    def selectActor(self,actor,clearList):
        if not actor.isSelectable:
            print "Error, not selectable ! "
            return False
        if clearList:
            self.clearSelected()
        
        self.selectedActors.append(actor)
        #self.push_handlers(actor)
        actor.setSelected(True)
        return True            
    
    def clearSelected(self):
        
        for a in self.selectedActors:
            a.setSelected(False)
            #self.remove_handlers(a)
        self.selectedActors[:]=[]    
        
    def doSelectionRectangle(self,box):

        list=[]
        
        s=1
        
        x1,y1=box[0]
        x2,y2=box[1]
        d=(x2-x1)**2+(y2-y1)**2    
        if d<0.01:
            x=x1
            y=y1
            x1-=s
            y1-=s
            x2=x+s
            y2=y+s
            
        for o in self.actors:
            if o.isSelectable:
                x,y=o.getPosition(True)
                if (x1<x<x2) and (y1<y<y2):
                    list.append(o)
        
        return list                

class SubWindow(object):
    def __init__(self,iGS,iPos,iSize):
        self.position=iPos
        self.size=iSize
        self.gameState=iGS
        self.screenCenter=(iSize[0]//2,iSize[1]//2)

    def isScreenPointIn(self,iPos):
        x,y=iPos
        w,h=self.size
        x-=self.position[0]
        y-=self.position[1]
        
        if 0<=x<w and 0<=y<h :
            return (x,y)
        return None
    
    def getRelativeScreenCoord(self,iPt):
        relPos=self.isScreenPointIn(iPt)
        if not relPos:
            print "error, point outside window"
            return None
        
        x,y=relPos
        w,h=self.size
        u = float(x) / float(w)
        v = float(y) / float(h)
        return (u,v)

    def prepareView(self):
        """
        Updates the view offset based on the center of the screen.

        Recalculates the necessary projection.
        """
        gl.glViewport(self.position[0],self.position[1], self.size[0],self.size[1])
        
        gl.glMatrixMode(gl.GL_PROJECTION)
        gl.glLoadIdentity()

        
        gl.gluOrtho2D(  0,self.size[0],0,self.size[1])
        
        gl.glMatrixMode(gl.GL_MODELVIEW)
        gl.glLoadIdentity()
    
    def on_mouse_press(self, x, y, button, modifiers):
        rc=self.isScreenPointIn((x,y))
        print "mouse press"
        if not rc:
            print "Outside bounds"
            return False
        return False
    
    def on_mouse_release(self, x, y, button, modifiers):
        rc=self.isScreenPointIn((x,y))
        if not rc:
            return False
        return False
    
    def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
        rc=self.isScreenPointIn((x,y))
        if not rc:
            return False
        return False
    
    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        rc=self.isScreenPointIn((x,y))
        if not rc:
            return False
        return False
    
    
class SubWindowCP(SubWindow):
    def __init__(self,iGS,iPos,iSize,iCenter,iZoom,iTex):
        self.tex=iTex
        super(SubWindowCP,self).__init__(iGS,iPos,iSize)
        
        self.widgets=[]
        self.widgets.append(Button(self,(50,200),"rocker switch",self.gameState.spawnBomb))
        for w in self.widgets:
            self.gameState.window.push_handlers(w)
    
        
            
    def draw(self):
        """ Draws decoration elements"""
        
        self.tex.blit(*self.screenCenter)
        
        for w in self.widgets:
            w.draw()
            

class SubWindow3D(SubWindow):
    def __init__(self,iGS,iPos,iSize,iCenter,iZoom):
        super(SubWindow3D,self).__init__(iGS,iPos,iSize)
        
        self.viewCenter=iCenter
        self.zoom=iZoom
        self.viewFactor=25.0
        
        self.selectionBox=None
        
        self.calculateExtents()
        
        self.animCounter=10
        self.selectionBox=None
        self.boxMask=0x3F3F
        
    
    def calculateExtents(self):
        self.ratio = float(self.size[0]) / self.size[1]
        self.extents = (self.ratio * self.viewFactor*self.zoom, self.viewFactor*self.zoom)
        
        self.updateBounds()
        
    def updateBounds(self):
        
        self.lower = [a-b for a,b in zip(self.viewCenter , self.extents)]
        self.upper = [a+b for a,b in zip(self.viewCenter , self.extents)]
        self.viewOffset = [a-b/2 for a,b in zip(self.viewCenter,self.size)]

        
    def prepareView(self):
        """
        Updates the view offset based on the center of the screen.

        Recalculates the necessary projection.
        """
        
        
        gl.glViewport(self.position[0],self.position[1], self.size[0],self.size[1])

        gl.glMatrixMode(gl.GL_PROJECTION)
        gl.glLoadIdentity()

        
        # L/R/B/T
        gl.gluOrtho2D(  self.lower[0], self.upper[0],
                        self.lower[1], self.upper[1])
        #print "(Resize) View extents", lower, upper, "Ratio", ratio

        
        gl.glMatrixMode(gl.GL_MODELVIEW)
        gl.glLoadIdentity()
    
    
    def convertScreenToWorld(self, iPt):
        """
        Takes screen (x, y) and returns
        world coordinate b2Vec2(x',y').
        """
        rel=self.getRelativeScreenCoord(iPt)
        if not rel:
            return None
        u,v=rel
##        ratio = float(w) / h
##        extents = box2d.b2Vec2(ratio * 25.0, 25.0)
##        extents *= self.zoom
##
##        lower = self.viewCenter - extents
##        upper = self.viewCenter + extents

        p = box2d.b2Vec2()
        p.x = (1.0 - u) * self.lower[0] + u * self.upper[0]
        p.y = (1.0 - v) * self.lower[1] + v * self.upper[1]
        
        return p

    def convertWorldToScreen(self, p):
        """
        Takes world b2Vec2(x, y) and returns
        screen coordinate (x',y').
        """
        w,h=self.size
        
##        ratio = float(w) / h
##        
##        extents = box2d.b2Vec2(ratio * 25.0, 25.0)
##        extents *= self.viewZoom
##        lower = self.viewCenter - extents
##        upper = self.viewCenter + extents
        
        u=(p.x-self.lower[0])/(self.upper[0]-self.lower[0])
        v=(p.y-self.lower[1])/(self.upper[1]-self.lower[1])
        x=u*w+self.position[0]
        y=(1-v)*h+self.position[1]


        return (x,y)

    def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
        """
        Mouse scrollwheel used
        """
        rc=self.isScreenPointIn((x,y))
        if not rc:
            return False
        
        if scroll_y < 0:
            self.zoom *= 1.1
           
        elif scroll_y > 0:
            self.zoom *= 0.9
           
        self.calculateExtents()
        return True
    
    def on_mouse_press(self, x, y, button, modifiers):
        # ...
        p = self.convertScreenToWorld((x, y))
        
        if not p:
            return False
        
        if button & (pyglet.window.mouse.LEFT | pyglet.window.mouse.RIGHT):
            self.mouseWorldInitialPos=p
            if not self.selectionBox:
                self.selectionBox=box2d.b2AABB()
            self.selectionBox=[(p.x,p.y),(p.x,p.y)]
            if button & pyglet.window.mouse.LEFT:
                self.selectionTypeLeft=True
            else :
                self.selectionTypeLeft=False
        
            return True    
          
    def on_mouse_release(self, x, y, button, modifiers):
        """
        Mouse up
        """
        p = self.convertScreenToWorld((x, y))
        if not p:
            return False
        self.mouseWorld = p
        target=None
        if button & (pyglet.window.mouse.LEFT | pyglet.window.mouse.RIGHT):
            if self.selectionBox:
                list=self.gameState.doSelectionRectangle(self.selectionBox)
                if button & pyglet.window.mouse.LEFT and list:
                    self.gameState.clearSelected()
                    for o in list:
                        self.gameState.selectActor(o,False)
                if button & pyglet.window.mouse.RIGHT:
                    if len(self.gameState.selectedActors):
                        if list:
                            if len(list)>0:
                                target=list[0] #to be improved: actor should expect a list as target
                        data={}
                        data['Position']=p
                        if target :
                            data['Target']=target
                            print "New Target :"+target.name
                        else : 
                            data['Target']=None
                        data['Modifiers']=modifiers
                    
                        for a in self.gameState.selectedActors:
                            a.doAction(data)  
                self.mouseWorldInitialPos=None
                self.selectionBox=None
                return True
            return False
        return False

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        """
        Mouse moved while clicking
        """
        p = self.convertScreenToWorld((x, y))
        if not p:
            return False
        
        self.mouseWorld = p
        if buttons & (pyglet.window.mouse.LEFT | pyglet.window.mouse.RIGHT):

            self.selectionBox[0]=(
                min(self.mouseWorldInitialPos.x,self.mouseWorld.x),
                min(self.mouseWorldInitialPos.y,self.mouseWorld.y))
            self.selectionBox[1]=(
                max(self.mouseWorldInitialPos.x,self.mouseWorld.x),
                max(self.mouseWorldInitialPos.y,self.mouseWorld.y))
            return True
        """
        Mouse moved while clicking
        """
        
        

        if buttons & pyglet.window.mouse.MIDDLE:
            self.viewCenter[0] -= float(dx)*0.2
            self.viewCenter[1] -= float(dy)*0.2
            self.updateBounds()
            
        return True    
    
    def draw(self):
        """ Draws decoration elements"""
        
        if self.selectionBox:
            self.animCounter-=1
            
            if self.animCounter<=0:
                self.animCounter=10
                if self.boxMask&0x8000:
                    self.boxMask=self.boxMask<<1|1
                else:
                    self.boxMask=self.boxMask<<1

            bBox = pyglet.graphics.Batch()
            
            points=[
            self.selectionBox[0][0],self.selectionBox[0][1],
            self.selectionBox[1][0],self.selectionBox[0][1],
            self.selectionBox[1][0],self.selectionBox[1][1],
            self.selectionBox[0][0],self.selectionBox[1][1]]
            
           
            
            bBox.add(4,gl.GL_LINE_LOOP,None,('v2f',points),('c3f',[1.,0.7,0.]*4))
            gl.glPushAttrib(gl.GL_LINE_STIPPLE|gl.GL_BLEND|gl.GL_COLOR_BUFFER_BIT)
            gl.glEnable(gl.GL_LINE_STIPPLE)
            gl.glLineWidth(2)
            gl.glEnable(gl.GL_BLEND)
            gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        
            gl.glLineStipple(1,self.boxMask)
            bBox.draw()
            gl.glPopAttrib()

if __name__=="__main__":
    test = Main()
    test.run()
